Via 313 word cloud

Via 313 word cloud

 

Yelp.com has been a directory and review go-to for many years. A four-star app in both Google Play and the Apple Store, the company claims to be home to over 135 million reviews.

From the perspective of the consumer, positive reviews can lead to increased interest and patronage. The human phenomenon known as FOMO (the Fear Of Missing Out) keeps us alert of what others in our network enjoy taking part in and give us a kind of social incentive for keeping with the group. In contrast, poor reviews often signal unpleasant experiences from users that we may want to account for when choosing where to spend our money.

From the perspective of the business owner, online reviews have sort of become the digitized “word-of-mouth”. Naturally, the internet has made first-hand experiences with any product or company abundantly available on the web. With recent studies showing 95% of shoppers read online reviews before making a purchase, it’s no wonder services like Yelp are becoming increasingly important in customer experience analysis. Any successful business must inspire loyalty in its customers; to do that we must find a way to tap into the emotions our services evoke in our customers and the language they use when describing our business.

Business Challenge

As a business owner, how can I get a snapshot of what my customers are saying on Yelp.com?

In this analysis, I try to provide a data-mining alternative to the manual, labor-intensive process of reading every review. Of course, there is a time for engaging with your customers and addressing their experiences online and in person. However, a primary goal of business intelligence is to bring together insightful and actionable information for key decision makers. To that end, this project aims to give an overall sense of reviews from Yelp.com for a pizza chain in Austin, TX.

 

Data Challenge

Mining Messy Yelp.com Data for Sentiment and Term Frequency

As a broke college student, I must admit that pizza is a go-to for my colleagues and I. Yelp can help navigate the price points and experiences of competitive pizzerias in the area. For this customer experience analysis, I will borrow the URL of Yelp.com reviews for Via 313 Pizza in Austin, TX. I will then attempt to clean the data from multiple pages of reviews to construct a Document-Term-Matrix that will be used to provide us with text-based insight.

# Libraries
library(XML)
library(RCurl)
library(ggplot2)
library(syuzhet)
library(tm)
library(SnowballC)
library(wordcloud2)

# Yelp pizzeria URLs
viaURL <- 'https://www.yelp.com/biz/via-313-pizza-north-campus-austin' # 487 Reviews

Cleaning Text Data

Since I will be using the pizzeria comments from Yelp.com, I can use RCurl and XML to scrape the URLs for reviews and then clean their syntax for a more readable format that can be easily measured. The reviews are returned in lower case words with no numbers or punctuation. Here is an example of the first few cleaned reviews.

# Set URL
url <- viaURL

# Create empty data frame for reviews
reviewsDF <- data.frame()

# Get data and convert to data frame
reviewsPage <- getURL(url)
parsedReviews <- htmlParse(reviewsPage)
reviews <- xpathSApply(parsedReviews, '//div[@itemtype="http://schema.org/Review"]', xmlValue) 
reviewsDF <- data.frame(reviews)

# Set number of additional pages for more reviews (20 per page)
for (i in 1:2) {
  # Set URL
  url <- paste('https://www.yelp.com/biz/via-313-pizza-north-campus-austin?start=', i*20, sep="")
  reviewsPage <- getURL(url)
  parsedReviews<-htmlParse(reviewsPage)
  reviews <- xpathSApply(parsedReviews, '//div[@itemtype="http://schema.org/Review"]', xmlValue)
  reviews <- data.frame(reviews)
  reviewsDF <- rbind(reviewsDF, reviews)
}

# catch.error() function to check and convert to lower case
catch.error <- function(x)
{
  y <- NA
  catch_error <- tryCatch(tolower(x), error=function(e) e)
  if (!inherits(catch_error, "error"))
    y <- tolower(x)
  return(y)
}

# cleanReviews() function removes superfluous characters
cleanReviews <- function(review){
  review = gsub("\n", " ", review)
  review = gsub("[[:punct:]]", " ", review)
  review = gsub("[[:digit:]]", " ", review)
  review = iconv(review, "UTF-8", "ascii",sub='')
  review = catch.error(review)
  review
}

# cleanReviewsAndRemoveNAs() function removes NA or duplicates
cleanReviewsAndRemoveNAs <- function (allReviews) {
  allReviewsCleaned <- sapply(allReviews, cleanReviews)
  allReviewsCleaned <- allReviewsCleaned[!is.na(allReviewsCleaned)]
  names(allReviewsCleaned) = NULL
  allReviewsCleaned <- unique(allReviewsCleaned)
  allReviewsCleaned
}

# Clean the reviews
reviewsCleaned <- cleanReviewsAndRemoveNAs(reviewsDF)
head(reviewsCleaned)
[1] "                               this was first time experiencing detroit style pizza  i ve had chicago style  new york style  and papa murphy s    let me tell you  this pizza blows them all out of the park  the crispy  buttery sides make this pizza complete   the ambassador bridge is one of the best pizzas i ve ever had  and this place is so cool because they allow you to do a half and half pizza  my other half was the       pineapple does belong on pizza  with jalapenos   other than the pizza being incredible  the customer service was out of this world  every time my family is in town  i ve taken them their and were treated with a taste of a dessert or a sample of an appetizer  they even gave me a birthday card on my birthday  who does that   easily one of my favorite places in austin      "                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
[2] "                               fair warning  i am a pineapple jalapeno kinda gal   i have been to detroit quite a few times now and that is probably the only reason i did not think this place it was as great as many others  but it was pretty great for detroit style pizza not in detroit   i will say the reason i thought it was not up to par for me was because it was a little too saucy and a little too cheesy  don t judge   the only reason that was a problem for me was because i love detroit style pizza for the crust and too much cheese and sauce will take away from the crunch of the pizza  i also was not a fan of how the pineapples were rounds  i understand the aesthetic was better but i did not get a piece of pineapple in each bite  which was a real bummer  the whole pizza was kinda falling apart  but the flavors of the crust and sauce were definitely up to par      "                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
[3] "                               detroit style pizza in austin  now we re talking    via     s rise in the city by providing delicious square pizzas has catapulted them to new heights  they ve managed to open several locations in just the last few years but the north campus location is the original and by far the most popular    i have to admit  i am a sucker for square slices  especially ones like detroit style  having had the real thing myself       i can vouch and say this is the real deal  the sauce is a little on the sweet side  but i love the crunch of the crust and how amazing the taste is  especially out of the oven  the toppings are a little on the fancier side than one would find in a classic detroit pizza parlor  but via     expands on the variety and really provides combinations that pack a punch for all palates   there is a soft spot in my stomach for the carnivore  which could probably be more abundant with the toppings  but it is truly the ultimate pizza to order here  right next to it is the ambassador bridge  which is basically the carnivore with added chopped garlic  coming in a very close second is the cadillac  which has gorgonzola  fig preserves  prosciutto di parma  parmesan  and balsamic glaze  a classic is  the detroiter  which includes two kinds of pepperoni  one smoked under the cheese  and naturally very curly pepperoni  it s so good   an   square  aka   x    runs anywhere from         where as the   square  aka  x    is meant to be a personal size runs from        no one ever said pizza was cheap  especially the good stuff  service is usually some college aged person taking orders behind the counter and most of the staff is pretty hip  while it s understandably not open as late as the east side location  i still give this north campus a big thumbs up                   is there such a thing as too many times      "
[4] "                               loved it  loved it  loved it     if you are looking for fabulous tasting gf pizza  this is it   their crust takes like the regular buttery  thick yummy crust that i no longer eat    the other reviews on yelp are true    this place is so good  we look forward to more visits    this place was a hit for the whole family  there was something for everyone   we went to the location close to ut campus on a sunday for dinner when the students were out so there was no wait for dinner time  however  i wouldn t expect that to be the case when school is back in session      "                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
[5] "                               ugh i love you via  best pizza i ve ever had hands down  my favorite is the cadillac which has gorgonzola and fig and sometimes i add ricotta to it which makes it super extra yummy   also their ranch    idk what the hell they do to it  but man it s the best ranch i ve ever had  i could drink this ranch   definitely get an order of cheese sticks with ran     "                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
[6] "                               detroit styled pizza in austin  not sure what that even means  but sign me up   i m usually not a fan of thick pizza because it leaves me feeling extremely sleepy and heavy  but via     did a great job  we ordered the hawaiian and the carnivore   both delicious  the italian salad was basic and fresh  and we were offered free cheese bread by our server   overall  a great meal      "                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                

Now we have clean text data to work with!

Data Solution

Customer Experience Analysis - Via 313 Pizza

Customer Language by Emotional Association

To chart customer experiences by grouping emotional terms, I can use the syuzhet package to group terms according to an associated NRC sentiment dictionary. After summing the frequencies of each emotional category, we can generate a nice bar chart of the customer emotions in Via 313 Pizza reviews.

# Obtain emotion frequency per review
reviewsEmotions <- get_nrc_sentiment(as.character(reviewsCleaned)) 
reviewsEmotionsDF <- t(data.frame(reviewsEmotions))

# Calculate number of reviews with each emotion > 0
reviewsEmotionsDFCount <- data.frame(rownames(reviewsEmotionsDF), 
                                     rowSums(reviewsEmotionsDF > 0))
rownames(reviewsEmotionsDFCount) <- NULL
colnames(reviewsEmotionsDFCount) <- c('Emotion','Frequency')

# Barplot of review sentiment
par(mar = c(3,6,1,1))

barplot(reviewsEmotionsDFCount$Frequency, 
        names.arg = reviewsEmotionsDFCount$Emotion,
        col = "lightblue",
        horiz = TRUE,
        main ="Customer Emotions - Via 313 Pizza", 
        cex.names = 1,
        las = 2)

As we can see from the chart, leading emotions from customer reviews are positive. They signal trust, joy and anticipation when describing their experiences at Via 313 Pizza.

Most Frequently Used Words

Next, we can use the tm package to take a closer look at the most frequent words used in the reviews and generate a bar chart of those terms.

# Create text corpus of reviews
reviews_corp <- Corpus(VectorSource(reviewsCleaned))

# Remove stopwords and create document-term matrix
reviews_DTM <- DocumentTermMatrix(reviews_corp,
                                  control = list(stopwords=T))

# Find frequent terms (cutoff frequency is 50)
findFreqTerms(reviews_DTM, lowfreq = 50)
# Sum up frequencies review and then sort in descending order
reviews_FreqTerms <- sort(rowSums(t(as.matrix(reviews_DTM))), decreasing=TRUE)

# Create data frame with two columns: word and frequency
reviews_FreqTermsDF <- data.frame(word = names(reviews_FreqTerms),
                                  freq = reviews_FreqTerms)
row.names(reviews_FreqTermsDF) <- NULL

# Plot the ten most frequently used words in reviews
barplot(reviews_FreqTermsDF[1:10,]$freq,
        las = 2,
        names.arg = reviews_FreqTermsDF[1:10,]$word,
        col ="lightblue", 
        main ="Most Frequent Words - Via 313 Pizza")

From the chart we can see that 313 Pizza is praised for its detroit-style pizza. People seem to love their crust, cheese, and service. Moreover, it is often praised as a place where customers had a great time or experience.

Word Cloud

Since I already have a word frequency data frame, I can use wordcloud2 to generate a nice visual component to the term frequencies.

# Create word cloud
wordcloud2(data = reviews_FreqTermsDF, size = 1.5)
Via 313 word cloud

Via 313 word cloud

Business Solution and Further

Via 313 Pizza seems to provide customers with a satisfying experience with both good food and a pleasant environment. Their signature detroit-style pizza and outstanding service has helped them earn 4.5 out of 5 stars.

To make this kind of analysis more impactful for the business, I would recommend building snapshots of customer ratings a monthly or even weekly business practice, depending on the availability of updated reviews. Additionally, I would recommend incorporating many more sources of reviews from social media outlets such as Twitter, Facebook, and Google. These modifications can help any business have a good idea of what their customers are talking about and may leverage this information to make a positive change in how they do business with customers.

LS0tDQp0aXRsZTogIk9yLCBob3cgdG8gdW5kZXJzdGFuZCB5b3VyIGN1c3RvbWVycycgZXhwZXJpZW5jZSB0aHJvdWdoIG1pbmluZyByZXZpZXdzIG9uIFllbHAuY29tIg0KZGF0ZTogMjAxOS0xMi0wNw0KdGFnczogW2J1c2luZXNzLCBubHAsIHNvY2lhbCBtZWRpYSBtaW5pbmddDQpoZWFkZXI6DQojICBpbWFnZTogIi9pbWFnZXMvZW5yb2xsbWVudEZvcmVjYXN0UGljLnBuZyINCmV4Y2VycHQ6ICJCdXNpbmVzcywgTkxQLCBTb2NpYWwgTWVkaWEgTWluaW5nIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCi0tLQ0KPGNlbnRlcj4NCg0KIVsqVmlhIDMxMyB3b3JkIGNsb3VkKl0oQzovVXNlcnMvZ2VvcmdlL0RvY3VtZW50cy9SIEFzc2lnbm1lbnRzL0VCQiBBTkQgRkxPVy9HZW9yZ2VBYXJvbkcuZ2l0aHViLmlvL2ltYWdlcy9waXp6YSBhbmFseXNpcy9WaWFXb3JkY2xvdWQyLnBuZykNCg0KPC9jZW50ZXI+DQoNCiZuYnNwOw0KDQpbWWVscC5jb21dKGh0dHBzOi8vd3d3LnllbHAuY29tLykgaGFzIGJlZW4gYSBkaXJlY3RvcnkgYW5kIHJldmlldyBnby10byBmb3IgbWFueSB5ZWFycy4gIEEgZm91ci1zdGFyIGFwcCBpbiBib3RoIFtHb29nbGUgUGxheV0oaHR0cHM6Ly9wbGF5Lmdvb2dsZS5jb20vc3RvcmUvYXBwcy9kZXRhaWxzP2lkPWNvbS55ZWxwLmFuZHJvaWQmaGw9ZW5fVVMpIGFuZCB0aGUgW0FwcGxlIFN0b3JlXShodHRwczovL2FwcHMuYXBwbGUuY29tL3VzL2FwcC95ZWxwLWZvb2Qtc2VydmljZXMtYXJvdW5kLW1lL2lkMjg0OTEwMzUwKSwgdGhlIGNvbXBhbnkgY2xhaW1zIHRvIGJlIGhvbWUgdG8gb3ZlciAxMzUgbWlsbGlvbiByZXZpZXdzLiAgDQoNCkZyb20gdGhlIHBlcnNwZWN0aXZlIG9mIHRoZSBjb25zdW1lciwgcG9zaXRpdmUgcmV2aWV3cyBjYW4gbGVhZCB0byBpbmNyZWFzZWQgaW50ZXJlc3QgYW5kIHBhdHJvbmFnZS4gIFRoZSBodW1hbiBwaGVub21lbm9uIGtub3duIGFzICoqRk9NTyoqICh0aGUgRmVhciBPZiBNaXNzaW5nIE91dCkga2VlcHMgdXMgYWxlcnQgb2Ygd2hhdCBvdGhlcnMgaW4gb3VyIG5ldHdvcmsgZW5qb3kgdGFraW5nIHBhcnQgaW4gYW5kIGdpdmUgdXMgYSBraW5kIG9mIHNvY2lhbCBpbmNlbnRpdmUgZm9yIGtlZXBpbmcgd2l0aCB0aGUgZ3JvdXAuICBJbiBjb250cmFzdCwgcG9vciByZXZpZXdzIG9mdGVuIHNpZ25hbCB1bnBsZWFzYW50IGV4cGVyaWVuY2VzIGZyb20gdXNlcnMgdGhhdCB3ZSBtYXkgd2FudCB0byBhY2NvdW50IGZvciB3aGVuIGNob29zaW5nIHdoZXJlIHRvIHNwZW5kIG91ciBtb25leS4NCg0KRnJvbSB0aGUgcGVyc3BlY3RpdmUgb2YgdGhlIGJ1c2luZXNzIG93bmVyLCBvbmxpbmUgcmV2aWV3cyBoYXZlIHNvcnQgb2YgYmVjb21lIHRoZSBkaWdpdGl6ZWQgIndvcmQtb2YtbW91dGgiLiAgTmF0dXJhbGx5LCB0aGUgaW50ZXJuZXQgaGFzIG1hZGUgZmlyc3QtaGFuZCBleHBlcmllbmNlcyB3aXRoIGFueSBwcm9kdWN0IG9yIGNvbXBhbnkgYWJ1bmRhbnRseSBhdmFpbGFibGUgb24gdGhlIHdlYi4gIFtXaXRoIHJlY2VudCBzdHVkaWVzIHNob3dpbmcgOTUlIG9mIHNob3BwZXJzIHJlYWQgb25saW5lIHJldmlld3MgYmVmb3JlIG1ha2luZyBhIHB1cmNoYXNlXShodHRwczovL3NwaWVnZWwubWVkaWxsLm5vcnRod2VzdGVybi5lZHUvX3BkZi9TcGllZ2VsX09ubGluZSUyMFJldmlld19lQm9va19KdW4yMDE3X0ZJTkFMLnBkZiksIGl0J3Mgbm8gd29uZGVyIHNlcnZpY2VzIGxpa2UgWWVscCBhcmUgYmVjb21pbmcgaW5jcmVhc2luZ2x5IGltcG9ydGFudCBpbiBjdXN0b21lciBleHBlcmllbmNlIGFuYWx5c2lzLiAgQW55IHN1Y2Nlc3NmdWwgYnVzaW5lc3MgbXVzdCBpbnNwaXJlIGxveWFsdHkgaW4gaXRzIGN1c3RvbWVyczsgdG8gZG8gdGhhdCB3ZSBtdXN0IGZpbmQgYSB3YXkgdG8gdGFwIGludG8gdGhlIGVtb3Rpb25zIG91ciBzZXJ2aWNlcyBldm9rZSBpbiBvdXIgY3VzdG9tZXJzIGFuZCB0aGUgbGFuZ3VhZ2UgdGhleSB1c2Ugd2hlbiBkZXNjcmliaW5nIG91ciBidXNpbmVzcy4NCg0KIyBCdXNpbmVzcyBDaGFsbGVuZ2UNCg0KPiBBcyBhIGJ1c2luZXNzIG93bmVyLCBob3cgY2FuIEkgZ2V0IGEgc25hcHNob3Qgb2Ygd2hhdCBteSBjdXN0b21lcnMgYXJlIHNheWluZyBvbiBZZWxwLmNvbT8NCg0KSW4gdGhpcyBhbmFseXNpcywgSSB0cnkgdG8gcHJvdmlkZSBhIGRhdGEtbWluaW5nIGFsdGVybmF0aXZlIHRvIHRoZSBtYW51YWwsIGxhYm9yLWludGVuc2l2ZSBwcm9jZXNzIG9mIHJlYWRpbmcgZXZlcnkgcmV2aWV3LiAgT2YgY291cnNlLCB0aGVyZSBpcyBhIHRpbWUgZm9yIGVuZ2FnaW5nIHdpdGggeW91ciBjdXN0b21lcnMgYW5kIGFkZHJlc3NpbmcgdGhlaXIgZXhwZXJpZW5jZXMgb25saW5lIGFuZCBpbiBwZXJzb24uICBIb3dldmVyLCBhIHByaW1hcnkgZ29hbCBvZiBidXNpbmVzcyBpbnRlbGxpZ2VuY2UgaXMgdG8gYnJpbmcgdG9nZXRoZXIgaW5zaWdodGZ1bCBhbmQgYWN0aW9uYWJsZSBpbmZvcm1hdGlvbiBmb3Iga2V5IGRlY2lzaW9uIG1ha2Vycy4gIFRvIHRoYXQgZW5kLCAqKnRoaXMgcHJvamVjdCBhaW1zIHRvIGdpdmUgYW4gb3ZlcmFsbCBzZW5zZSBvZiByZXZpZXdzIGZyb20gWWVscC5jb20gZm9yIGEgcGl6emEgY2hhaW4gaW4gQXVzdGluLCBUWCoqLg0KDQombmJzcDsNCg0KIyBEYXRhIENoYWxsZW5nZQ0KDQojIyMgTWluaW5nIE1lc3N5IFllbHAuY29tIERhdGEgZm9yIFNlbnRpbWVudCBhbmQgVGVybSBGcmVxdWVuY3kNCg0KQXMgYSBicm9rZSBjb2xsZWdlIHN0dWRlbnQsIEkgbXVzdCBhZG1pdCB0aGF0IHBpenphIGlzIGEgZ28tdG8gZm9yIG15IGNvbGxlYWd1ZXMgYW5kIEkuICBZZWxwIGNhbiBoZWxwIG5hdmlnYXRlIHRoZSBwcmljZSBwb2ludHMgYW5kIGV4cGVyaWVuY2VzIG9mIGNvbXBldGl0aXZlIHBpenplcmlhcyBpbiB0aGUgYXJlYS4gIEZvciB0aGlzIGN1c3RvbWVyIGV4cGVyaWVuY2UgYW5hbHlzaXMsIEkgd2lsbCBib3Jyb3cgdGhlIFVSTCBvZiBZZWxwLmNvbSByZXZpZXdzIGZvciBWaWEgMzEzIFBpenphIGluIEF1c3RpbiwgVFguICBJIHdpbGwgdGhlbiBhdHRlbXB0IHRvIGNsZWFuIHRoZSBkYXRhIGZyb20gbXVsdGlwbGUgcGFnZXMgb2YgcmV2aWV3cyB0byBjb25zdHJ1Y3QgYSAqRG9jdW1lbnQtVGVybS1NYXRyaXgqIHRoYXQgd2lsbCBiZSB1c2VkIHRvIHByb3ZpZGUgdXMgd2l0aCB0ZXh0LWJhc2VkIGluc2lnaHQuDQoNCmBgYHtyIG1lc3NhZ2UgPSAgRkFMU0V9DQojIExpYnJhcmllcw0KbGlicmFyeShYTUwpDQpsaWJyYXJ5KFJDdXJsKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzeXV6aGV0KQ0KbGlicmFyeSh0bSkNCmxpYnJhcnkoU25vd2JhbGxDKQ0KbGlicmFyeSh3b3JkY2xvdWQyKQ0KDQojIFllbHAgcGl6emVyaWEgVVJMcw0KdmlhVVJMIDwtICdodHRwczovL3d3dy55ZWxwLmNvbS9iaXovdmlhLTMxMy1waXp6YS1ub3J0aC1jYW1wdXMtYXVzdGluJyAjIDQ4NyBSZXZpZXdzDQpgYGANCg0KIyMjIENsZWFuaW5nIFRleHQgRGF0YQ0KDQpTaW5jZSBJIHdpbGwgYmUgdXNpbmcgdGhlIHBpenplcmlhIGNvbW1lbnRzIGZyb20gWWVscC5jb20sIEkgY2FuIHVzZSAqUkN1cmwqIGFuZCAqWE1MKiB0byBzY3JhcGUgdGhlIFVSTHMgZm9yIHJldmlld3MgYW5kIHRoZW4gY2xlYW4gdGhlaXIgc3ludGF4IGZvciBhIG1vcmUgcmVhZGFibGUgZm9ybWF0IHRoYXQgY2FuIGJlIGVhc2lseSBtZWFzdXJlZC4gIFRoZSByZXZpZXdzIGFyZSByZXR1cm5lZCBpbiBsb3dlciBjYXNlIHdvcmRzIHdpdGggbm8gbnVtYmVycyBvciBwdW5jdHVhdGlvbi4gIEhlcmUgaXMgYW4gZXhhbXBsZSBvZiB0aGUgZmlyc3QgZmV3IGNsZWFuZWQgcmV2aWV3cy4NCmBgYHtyfQ0KIyBTZXQgVVJMDQp1cmwgPC0gdmlhVVJMDQoNCiMgQ3JlYXRlIGVtcHR5IGRhdGEgZnJhbWUgZm9yIHJldmlld3MNCnJldmlld3NERiA8LSBkYXRhLmZyYW1lKCkNCg0KIyBHZXQgZGF0YSBhbmQgY29udmVydCB0byBkYXRhIGZyYW1lDQpyZXZpZXdzUGFnZSA8LSBnZXRVUkwodXJsKQ0KcGFyc2VkUmV2aWV3cyA8LSBodG1sUGFyc2UocmV2aWV3c1BhZ2UpDQpyZXZpZXdzIDwtIHhwYXRoU0FwcGx5KHBhcnNlZFJldmlld3MsICcvL2RpdltAaXRlbXR5cGU9Imh0dHA6Ly9zY2hlbWEub3JnL1JldmlldyJdJywgeG1sVmFsdWUpIA0KcmV2aWV3c0RGIDwtIGRhdGEuZnJhbWUocmV2aWV3cykNCg0KIyBTZXQgbnVtYmVyIG9mIGFkZGl0aW9uYWwgcGFnZXMgZm9yIG1vcmUgcmV2aWV3cyAoMjAgcGVyIHBhZ2UpDQpmb3IgKGkgaW4gMToyKSB7DQogICMgU2V0IFVSTA0KICB1cmwgPC0gcGFzdGUoJ2h0dHBzOi8vd3d3LnllbHAuY29tL2Jpei92aWEtMzEzLXBpenphLW5vcnRoLWNhbXB1cy1hdXN0aW4/c3RhcnQ9JywgaSoyMCwgc2VwPSIiKQ0KICByZXZpZXdzUGFnZSA8LSBnZXRVUkwodXJsKQ0KICBwYXJzZWRSZXZpZXdzPC1odG1sUGFyc2UocmV2aWV3c1BhZ2UpDQogIHJldmlld3MgPC0geHBhdGhTQXBwbHkocGFyc2VkUmV2aWV3cywgJy8vZGl2W0BpdGVtdHlwZT0iaHR0cDovL3NjaGVtYS5vcmcvUmV2aWV3Il0nLCB4bWxWYWx1ZSkNCiAgcmV2aWV3cyA8LSBkYXRhLmZyYW1lKHJldmlld3MpDQogIHJldmlld3NERiA8LSByYmluZChyZXZpZXdzREYsIHJldmlld3MpDQp9DQoNCiMgY2F0Y2guZXJyb3IoKSBmdW5jdGlvbiB0byBjaGVjayBhbmQgY29udmVydCB0byBsb3dlciBjYXNlDQpjYXRjaC5lcnJvciA8LSBmdW5jdGlvbih4KQ0Kew0KICB5IDwtIE5BDQogIGNhdGNoX2Vycm9yIDwtIHRyeUNhdGNoKHRvbG93ZXIoeCksIGVycm9yPWZ1bmN0aW9uKGUpIGUpDQogIGlmICghaW5oZXJpdHMoY2F0Y2hfZXJyb3IsICJlcnJvciIpKQ0KICAgIHkgPC0gdG9sb3dlcih4KQ0KICByZXR1cm4oeSkNCn0NCg0KIyBjbGVhblJldmlld3MoKSBmdW5jdGlvbiByZW1vdmVzIHN1cGVyZmx1b3VzIGNoYXJhY3RlcnMNCmNsZWFuUmV2aWV3cyA8LSBmdW5jdGlvbihyZXZpZXcpew0KICByZXZpZXcgPSBnc3ViKCJcbiIsICIgIiwgcmV2aWV3KQ0KICByZXZpZXcgPSBnc3ViKCJbWzpwdW5jdDpdXSIsICIgIiwgcmV2aWV3KQ0KICByZXZpZXcgPSBnc3ViKCJbWzpkaWdpdDpdXSIsICIgIiwgcmV2aWV3KQ0KICByZXZpZXcgPSBpY29udihyZXZpZXcsICJVVEYtOCIsICJhc2NpaSIsc3ViPScnKQ0KICByZXZpZXcgPSBjYXRjaC5lcnJvcihyZXZpZXcpDQogIHJldmlldw0KfQ0KDQojIGNsZWFuUmV2aWV3c0FuZFJlbW92ZU5BcygpIGZ1bmN0aW9uIHJlbW92ZXMgTkEgb3IgZHVwbGljYXRlcw0KY2xlYW5SZXZpZXdzQW5kUmVtb3ZlTkFzIDwtIGZ1bmN0aW9uIChhbGxSZXZpZXdzKSB7DQogIGFsbFJldmlld3NDbGVhbmVkIDwtIHNhcHBseShhbGxSZXZpZXdzLCBjbGVhblJldmlld3MpDQogIGFsbFJldmlld3NDbGVhbmVkIDwtIGFsbFJldmlld3NDbGVhbmVkWyFpcy5uYShhbGxSZXZpZXdzQ2xlYW5lZCldDQogIG5hbWVzKGFsbFJldmlld3NDbGVhbmVkKSA9IE5VTEwNCiAgYWxsUmV2aWV3c0NsZWFuZWQgPC0gdW5pcXVlKGFsbFJldmlld3NDbGVhbmVkKQ0KICBhbGxSZXZpZXdzQ2xlYW5lZA0KfQ0KDQojIENsZWFuIHRoZSByZXZpZXdzDQpyZXZpZXdzQ2xlYW5lZCA8LSBjbGVhblJldmlld3NBbmRSZW1vdmVOQXMocmV2aWV3c0RGKQ0KaGVhZChyZXZpZXdzQ2xlYW5lZCkNCmBgYA0KTm93IHdlIGhhdmUgY2xlYW4gdGV4dCBkYXRhIHRvIHdvcmsgd2l0aCENCg0KIyBEYXRhIFNvbHV0aW9uDQoNCiMjIEN1c3RvbWVyIEV4cGVyaWVuY2UgQW5hbHlzaXMgLSBWaWEgMzEzIFBpenphDQoNCiMjIyBDdXN0b21lciBMYW5ndWFnZSBieSBFbW90aW9uYWwgQXNzb2NpYXRpb24NCg0KVG8gY2hhcnQgY3VzdG9tZXIgZXhwZXJpZW5jZXMgYnkgZ3JvdXBpbmcgZW1vdGlvbmFsIHRlcm1zLCBJIGNhbiB1c2UgdGhlICpzeXV6aGV0KiBwYWNrYWdlIHRvIGdyb3VwIHRlcm1zIGFjY29yZGluZyB0byBhbiBhc3NvY2lhdGVkICpOUkMqIHNlbnRpbWVudCBkaWN0aW9uYXJ5LiAgQWZ0ZXIgc3VtbWluZyB0aGUgZnJlcXVlbmNpZXMgb2YgZWFjaCBlbW90aW9uYWwgY2F0ZWdvcnksIHdlIGNhbiBnZW5lcmF0ZSBhIG5pY2UgYmFyIGNoYXJ0IG9mIHRoZSBjdXN0b21lciBlbW90aW9ucyBpbiBWaWEgMzEzIFBpenphIHJldmlld3MuDQpgYGB7ciwgcmVzdWx0cyA9IEZBTFNFfQ0KIyBPYnRhaW4gZW1vdGlvbiBmcmVxdWVuY3kgcGVyIHJldmlldw0KcmV2aWV3c0Vtb3Rpb25zIDwtIGdldF9ucmNfc2VudGltZW50KGFzLmNoYXJhY3RlcihyZXZpZXdzQ2xlYW5lZCkpIA0KcmV2aWV3c0Vtb3Rpb25zREYgPC0gdChkYXRhLmZyYW1lKHJldmlld3NFbW90aW9ucykpDQoNCiMgQ2FsY3VsYXRlIG51bWJlciBvZiByZXZpZXdzIHdpdGggZWFjaCBlbW90aW9uID4gMA0KcmV2aWV3c0Vtb3Rpb25zREZDb3VudCA8LSBkYXRhLmZyYW1lKHJvd25hbWVzKHJldmlld3NFbW90aW9uc0RGKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93U3VtcyhyZXZpZXdzRW1vdGlvbnNERiA+IDApKQ0Kcm93bmFtZXMocmV2aWV3c0Vtb3Rpb25zREZDb3VudCkgPC0gTlVMTA0KY29sbmFtZXMocmV2aWV3c0Vtb3Rpb25zREZDb3VudCkgPC0gYygnRW1vdGlvbicsJ0ZyZXF1ZW5jeScpDQoNCiMgQmFycGxvdCBvZiByZXZpZXcgc2VudGltZW50DQpwYXIobWFyID0gYygzLDYsMSwxKSkNCg0KYmFycGxvdChyZXZpZXdzRW1vdGlvbnNERkNvdW50JEZyZXF1ZW5jeSwgDQogICAgICAgIG5hbWVzLmFyZyA9IHJldmlld3NFbW90aW9uc0RGQ291bnQkRW1vdGlvbiwNCiAgICAgICAgY29sID0gImxpZ2h0Ymx1ZSIsDQogICAgICAgIGhvcml6ID0gVFJVRSwNCiAgICAgICAgbWFpbiA9IkN1c3RvbWVyIEVtb3Rpb25zIC0gVmlhIDMxMyBQaXp6YSIsIA0KICAgICAgICBjZXgubmFtZXMgPSAxLA0KICAgICAgICBsYXMgPSAyKQ0KYGBgDQpBcyB3ZSBjYW4gc2VlIGZyb20gdGhlIGNoYXJ0LCBsZWFkaW5nIGVtb3Rpb25zIGZyb20gY3VzdG9tZXIgcmV2aWV3cyBhcmUgcG9zaXRpdmUuICBUaGV5IHNpZ25hbCB0cnVzdCwgam95IGFuZCBhbnRpY2lwYXRpb24gd2hlbiBkZXNjcmliaW5nIHRoZWlyIGV4cGVyaWVuY2VzIGF0IFZpYSAzMTMgUGl6emEuDQoNCiMjIyBNb3N0IEZyZXF1ZW50bHkgVXNlZCBXb3Jkcw0KDQpOZXh0LCB3ZSBjYW4gdXNlIHRoZSAqdG0qIHBhY2thZ2UgdG8gdGFrZSBhIGNsb3NlciBsb29rIGF0IHRoZSBtb3N0IGZyZXF1ZW50IHdvcmRzIHVzZWQgaW4gdGhlIHJldmlld3MgYW5kIGdlbmVyYXRlIGEgYmFyIGNoYXJ0IG9mIHRob3NlIHRlcm1zLg0KYGBge3IsIHJlc3VsdHMgPSBGQUxTRX0NCiMgQ3JlYXRlIHRleHQgY29ycHVzIG9mIHJldmlld3MNCnJldmlld3NfY29ycCA8LSBDb3JwdXMoVmVjdG9yU291cmNlKHJldmlld3NDbGVhbmVkKSkNCg0KIyBSZW1vdmUgc3RvcHdvcmRzIGFuZCBjcmVhdGUgZG9jdW1lbnQtdGVybSBtYXRyaXgNCnJldmlld3NfRFRNIDwtIERvY3VtZW50VGVybU1hdHJpeChyZXZpZXdzX2NvcnAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3Qoc3RvcHdvcmRzPVQpKQ0KDQojIEZpbmQgZnJlcXVlbnQgdGVybXMgKGN1dG9mZiBmcmVxdWVuY3kgaXMgNTApDQpmaW5kRnJlcVRlcm1zKHJldmlld3NfRFRNLCBsb3dmcmVxID0gNTApDQoNCiMgU3VtIHVwIGZyZXF1ZW5jaWVzIHJldmlldyBhbmQgdGhlbiBzb3J0IGluIGRlc2NlbmRpbmcgb3JkZXINCnJldmlld3NfRnJlcVRlcm1zIDwtIHNvcnQocm93U3Vtcyh0KGFzLm1hdHJpeChyZXZpZXdzX0RUTSkpKSwgZGVjcmVhc2luZz1UUlVFKQ0KDQojIENyZWF0ZSBkYXRhIGZyYW1lIHdpdGggdHdvIGNvbHVtbnM6IHdvcmQgYW5kIGZyZXF1ZW5jeQ0KcmV2aWV3c19GcmVxVGVybXNERiA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyhyZXZpZXdzX0ZyZXFUZXJtcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJlcSA9IHJldmlld3NfRnJlcVRlcm1zKQ0Kcm93Lm5hbWVzKHJldmlld3NfRnJlcVRlcm1zREYpIDwtIE5VTEwNCg0KIyBQbG90IHRoZSB0ZW4gbW9zdCBmcmVxdWVudGx5IHVzZWQgd29yZHMgaW4gcmV2aWV3cw0KYmFycGxvdChyZXZpZXdzX0ZyZXFUZXJtc0RGWzE6MTAsXSRmcmVxLA0KICAgICAgICBsYXMgPSAyLA0KICAgICAgICBuYW1lcy5hcmcgPSByZXZpZXdzX0ZyZXFUZXJtc0RGWzE6MTAsXSR3b3JkLA0KICAgICAgICBjb2wgPSJsaWdodGJsdWUiLCANCiAgICAgICAgbWFpbiA9Ik1vc3QgRnJlcXVlbnQgV29yZHMgLSBWaWEgMzEzIFBpenphIikNCmBgYA0KRnJvbSB0aGUgY2hhcnQgd2UgY2FuIHNlZSB0aGF0IDMxMyBQaXp6YSBpcyBwcmFpc2VkIGZvciBpdHMgZGV0cm9pdC1zdHlsZSBwaXp6YS4gIFBlb3BsZSBzZWVtIHRvIGxvdmUgdGhlaXIgY3J1c3QsIGNoZWVzZSwgYW5kIHNlcnZpY2UuICBNb3Jlb3ZlciwgaXQgaXMgb2Z0ZW4gcHJhaXNlZCBhcyBhIHBsYWNlIHdoZXJlIGN1c3RvbWVycyBoYWQgYSBncmVhdCB0aW1lIG9yIGV4cGVyaWVuY2UuDQoNCiMjIyBXb3JkIENsb3VkDQoNClNpbmNlIEkgYWxyZWFkeSBoYXZlIGEgd29yZCBmcmVxdWVuY3kgZGF0YSBmcmFtZSwgSSBjYW4gdXNlICp3b3JkY2xvdWQyKiB0byBnZW5lcmF0ZSBhIG5pY2UgdmlzdWFsIGNvbXBvbmVudCB0byB0aGUgdGVybSBmcmVxdWVuY2llcy4NCmBgYHtyIHJlc3VsdHMgPSBGQUxTRX0NCiMgQ3JlYXRlIHdvcmQgY2xvdWQNCndvcmRjbG91ZDIoZGF0YSA9IHJldmlld3NfRnJlcVRlcm1zREYsIHNoYXBlID0gJ3RyaWFuZ2xlLWZvcndhcmQnLCBzaXplID0gMSkNCmBgYA0KIVsqVmlhIDMxMyB3b3JkIGNsb3VkKl0oQzovVXNlcnMvZ2VvcmdlL0RvY3VtZW50cy9SIEFzc2lnbm1lbnRzL0VCQiBBTkQgRkxPVy9HZW9yZ2VBYXJvbkcuZ2l0aHViLmlvL2ltYWdlcy9waXp6YSBhbmFseXNpcy9WaWFXb3JkY2xvdWQyLnBuZykNCg0KIyBCdXNpbmVzcyBTb2x1dGlvbiBhbmQgRnVydGhlcg0KDQpWaWEgMzEzIFBpenphIHNlZW1zIHRvIHByb3ZpZGUgY3VzdG9tZXJzIHdpdGggYSAqKnNhdGlzZnlpbmcgZXhwZXJpZW5jZSB3aXRoIGJvdGggZ29vZCBmb29kIGFuZCBhIHBsZWFzYW50IGVudmlyb25tZW50LiAgVGhlaXIgc2lnbmF0dXJlIGRldHJvaXQtc3R5bGUgcGl6emEgYW5kIG91dHN0YW5kaW5nIHNlcnZpY2UgaGFzIGhlbHBlZCB0aGVtIGVhcm4gNC41IG91dCBvZiA1IHN0YXJzLioqDQoNClRvIG1ha2UgdGhpcyBraW5kIG9mIGFuYWx5c2lzIG1vcmUgaW1wYWN0ZnVsIGZvciB0aGUgYnVzaW5lc3MsIEkgd291bGQgcmVjb21tZW5kIGJ1aWxkaW5nIHNuYXBzaG90cyBvZiBjdXN0b21lciByYXRpbmdzIGEgbW9udGhseSBvciBldmVuIHdlZWtseSBidXNpbmVzcyBwcmFjdGljZSwgZGVwZW5kaW5nIG9uIHRoZSBhdmFpbGFiaWxpdHkgb2YgdXBkYXRlZCByZXZpZXdzLiAgQWRkaXRpb25hbGx5LCBJIHdvdWxkIHJlY29tbWVuZCBpbmNvcnBvcmF0aW5nIG1hbnkgbW9yZSBzb3VyY2VzIG9mIHJldmlld3MgZnJvbSBzb2NpYWwgbWVkaWEgb3V0bGV0cyBzdWNoIGFzIFR3aXR0ZXIsIEZhY2Vib29rLCBhbmQgR29vZ2xlLiAgVGhlc2UgbW9kaWZpY2F0aW9ucyBjYW4gaGVscCBhbnkgYnVzaW5lc3MgaGF2ZSBhIGdvb2QgaWRlYSBvZiB3aGF0IHRoZWlyIGN1c3RvbWVycyBhcmUgdGFsa2luZyBhYm91dCBhbmQgbWF5IGxldmVyYWdlIHRoaXMgaW5mb3JtYXRpb24gdG8gbWFrZSBhIHBvc2l0aXZlIGNoYW5nZSBpbiBob3cgdGhleSBkbyBidXNpbmVzcyB3aXRoIGN1c3RvbWVycy4=